package org.springblade.auth.granter;

import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import org.springblade.auth.constant.AuthConstant;
import org.springblade.auth.service.BladeUserDetails;
import org.springblade.auth.utils.TokenUtil;
import org.springblade.core.tool.api.R;
import org.springblade.core.tool.support.Kv;
import org.springblade.core.tool.utils.Func;
import org.springblade.core.tool.utils.StringUtil;
import org.springblade.core.tool.utils.WebUtil;
import org.springblade.system.user.entity.User;
import org.springblade.system.user.entity.UserInfo;
import org.springblade.system.user.feign.IUserClient;
import org.springframework.core.env.Environment;
import org.springframework.security.authentication.AbstractAuthenticationToken;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.oauth2.common.exceptions.InvalidGrantException;
import org.springframework.security.oauth2.provider.*;
import org.springframework.security.oauth2.provider.token.AbstractTokenGranter;
import org.springframework.security.oauth2.provider.token.AuthorizationServerTokenServices;

import javax.servlet.http.HttpServletRequest;
import java.util.LinkedHashMap;
import java.util.Map;

public class InspurTokenGranter extends AbstractTokenGranter {
	private static final String GRANT_TYPE = "inspur";
	private static final Integer AUTH_SUCCESS_CODE = 2000;

	private final IUserClient userClient;


	protected InspurTokenGranter(AuthorizationServerTokenServices tokenServices,
							   ClientDetailsService clientDetailsService,
							   OAuth2RequestFactory requestFactory,
							   IUserClient userClient) {
		super(tokenServices, clientDetailsService, requestFactory, GRANT_TYPE);
		this.userClient = userClient;
	}

	@Override
	protected OAuth2Authentication getOAuth2Authentication(ClientDetails client, TokenRequest tokenRequest) {
		// 请求头租户信息
		HttpServletRequest request = WebUtil.getRequest();
		String tenantId = Func.toStr(request.getHeader(TokenUtil.TENANT_HEADER_KEY), TokenUtil.DEFAULT_TENANT_ID);

		Map<String, String> parameters = new LinkedHashMap<>(tokenRequest.getRequestParameters());

		String ticket = parameters.get("tk");
		if (StringUtil.isEmpty(ticket)){
			throw new InvalidGrantException("缺少相关的认证参数");
		}

		// 组装数据
		/*
		<Result>
			<UserID>SYSTEMADMIN</UserID>
			<Certificate></Certificate>
			<expirationTime>1305680922471</expirationTime>
			<signatureValue>8989!30$99assa</signatureValue>
		</Result>
		 */
		String account = null;
		try {
			Document doc = Jsoup.parse(ticket);
			Elements elements = doc.getElementsByTag("Result");
			Element resultElement = elements.first();
			String userId = resultElement.getElementsByTag("UserID").text();
			String expirationTime = resultElement.getElementsByTag("expirationTime").text();
			String signatureValue = resultElement.getElementsByTag("signatureValue").text();
		}catch (Exception e){
			throw new InvalidGrantException("认证参数解析失败");
		}

		if(account == null){
			throw new InvalidGrantException("应用集成平台认证失败");
		}

		// 远程调用，获取认证信息
		R<UserInfo> result = userClient.userInfo(tenantId, account);
		BladeUserDetails bladeUserDetails;
		if (result.isSuccess()) {
			User user = result.getData().getUser();
			Kv detail = result.getData().getDetail();
			if (user == null || user.getId() == null || user.getAccount() == null) {
				throw new InvalidGrantException("认证失败, 党建系统不识别此用户");
			}
			if (StringUtil.isEmpty(user.getRoleId())){
				throw new InvalidGrantException("没有权限，请联系管理员！");
			}
			bladeUserDetails = new BladeUserDetails(user.getId(),
				tenantId, result.getData().getOauthId(), user.getName(), user.getRealName(),
				user.getDeptId(), user.getPostId(), user.getRoleId(), Func.join(result.getData().getRoles()),
				Func.toStr(user.getAvatar(), TokenUtil.DEFAULT_AVATAR),
				user.getAccount(), AuthConstant.ENCRYPT + user.getPassword(), detail, true,
				true, true, true,
				AuthorityUtils.commaSeparatedStringToAuthorityList(Func.join(result.getData().getRoles())));
		} else {
			throw new InvalidGrantException("认证失败, 党建系统异常");
		}

		// 组装认证数据，关闭密码校验
		Authentication userAuth = new UsernamePasswordAuthenticationToken(bladeUserDetails, null,
			bladeUserDetails.getAuthorities());
		((AbstractAuthenticationToken) userAuth).setDetails(parameters);
		OAuth2Request storedOAuth2Request = getRequestFactory().createOAuth2Request(client, tokenRequest);

		// 返回 OAuth2Authentication
		return new OAuth2Authentication(storedOAuth2Request, userAuth);
	}

}
